#include "ThreadPool.h"

ThreadPool::ThreadPool(size_t maxThreads) : m_stopflag(false), m_maxThreads(maxThreads), m_workingThreads(0), m_workers(),
                                                m_priorityTasks(), m_queue_mutex(), m_condition(),
                                                m_historyRecordEnabled(false), m_historyRecordLimit(100), m_historyRecordVectorMaxSize(m_historyRecordLimit+m_historyRecordLimit/2),m_historyRecordVector(),
                                                m_log_mutex()
{
  m_historyRecordVector.reserve(m_historyRecordVectorMaxSize);

  for (size_t i = 0; i < maxThreads; ++i) {
      m_workers.emplace_back(new ThreadWrapper);
      m_workers.back()->setmain([this](const std::atomic<bool>& stop_token) {
          while(!stop_token.load(std::memory_order_acquire)) {
              std::function<void()> task;
              {
                std::unique_lock<std::mutex> lock(this->m_queue_mutex);

                this->m_condition.wait(lock, [this, &stop_token]{ 
                    return this->m_stopflag.load(std::memory_order_acquire) || 
                           !this->m_priorityTasks.empty() ||
                           stop_token.load(std::memory_order_acquire);
                });

                if((this->m_stopflag.load(std::memory_order_acquire) && this->m_priorityTasks.empty()) || 
                    stop_token.load(std::memory_order_acquire))
                {
                    return;
                }

                if (!this->m_priorityTasks.empty()) {
                    _updateExecTime(this->m_priorityTasks.top());
                    Pri_Task task_copy = this->m_priorityTasks.top(); 
                    this->m_priorityTasks.pop();
                    task = std::move(task_copy.task);
                } else {
                    continue; 
                }
              }
              if (task) {
                  m_workingThreads.fetch_add(1, std::memory_order_release);
                  try {
                      task();
                  } catch (const std::exception& e) {
                     std::cerr << "Exception caught in thread pool task: " << e.what() << std::endl;
                  } catch (...) {
                     std::cerr << "Unknown exception caught in thread pool task." << std::endl;
                  }
                  m_workingThreads.fetch_sub(1, std::memory_order_release);
              }
          }
      });
      m_workers.back()->start();
  }
}
ThreadPool::~ThreadPool(){
  {
      std::unique_lock<std::mutex> lock(m_queue_mutex);
      m_stopflag.store(true, std::memory_order_release);
  }
  m_condition.notify_all();
  for(auto &_worker : m_workers) {
      _worker->stop();
  }
}
